<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>CREATE FUNCTION</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="REFENTRY">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="sql-createdomain.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="sql-createdomain.html">快退</a></td><td width="60%" align="center" valign="bottom"></td><td width="10%" align="right" valign="top"><a href="sql-creategroup.html">快进</a></td><td width="10%" align="right" valign="top"><a href="sql-creategroup.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<h1><a name="SQL-CREATEFUNCTION"></a>CREATE FUNCTION</h1>
<div class="REFNAMEDIV"><a name="AEN47138"></a><h2>名称</h2>CREATE FUNCTION&nbsp;--&nbsp;定义一个新函数</div>
<a name="AEN47141"></a>
<div class="REFSYNOPSISDIV"><a name="AEN47143"></a><h2>语法</h2>
<pre class="SYNOPSIS">CREATE [ OR REPLACE ] FUNCTION
    <tt class="REPLACEABLE"><i>name</i></tt> ( [ [ <tt class="REPLACEABLE"><i>argmode</i></tt> ] [ <tt class="REPLACEABLE"><i>argname</i></tt> ] <tt class="REPLACEABLE"><i>argtype</i></tt> [, ...] ] )
    [ RETURNS <tt class="REPLACEABLE"><i>rettype</i></tt> ]
  { LANGUAGE <tt class="REPLACEABLE"><i>langname</i></tt>
    | IMMUTABLE | STABLE | VOLATILE
    | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
    | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
    | AS '<tt class="REPLACEABLE"><i>definition</i></tt>'
    | AS '<tt class="REPLACEABLE"><i>obj_file</i></tt>', '<tt class="REPLACEABLE"><i>link_symbol</i></tt>'
  } ...
    [ WITH ( <tt class="REPLACEABLE"><i>attribute</i></tt> [, ...] ) ]</pre>
</div>
<div class="REFSECT1"><a name="SQL-CREATEFUNCTION-DESCRIPTION"></a><h2>描述</h2>
<p><tt class="COMMAND">CREATE FUNCTION</tt> 定义一个新的函数。<tt class="COMMAND">CREATE OR REPLACE FUNCTION</tt> 将要么创建一个新函数，要么替换现有的定义。</p>
<p>如果包含了一个模式名，那么函数就在指定的模式中创建。否则它会在当前模式中创建。新函数的名字不能和同一个模式中的任何带有同样参数类型的函数同名。不过，参数类型不同的函数可以同名(这叫做<i class="FIRSTTERM">重载</i>)。</p>
<p>使用 <tt class="COMMAND">CREATE OR REPLACE FUNCTION</tt> 更新一个现有函数的定义。不能用这个方法修改一个函数的名字或者参数类型，否则就会创建一个新的函数。同样，<tt class="COMMAND">CREATE OR REPLACE FUNCTION</tt> 也不会允许你修改一个现有函数的返回类型。要做这些事情，你必须删除并重新创建函数。如果使用 <tt class="LITERAL">OUT</tt> 参数，那就意味着除了删除函数之外，你不能修改任何 <tt class="LITERAL">OUT</tt> 参数的类型或者名字。</p>
<p>如果你删除然后重建一个函数，新函数和旧函数将是不同的实体；你就需要删除现有引用了老函数的规则、视图、触发器等等。使用 <tt class="COMMAND">CREATE OR REPLACE FUNCTION</tt> 可以在不破坏引用该函数的对象的前提下修改函数定义。</p>
<p>创建这个函数的用户将成为函数的所有者。</p>
</div>
<div class="REFSECT1"><a name="AEN47170"></a><h2>参数</h2>
<div class="VARIABLELIST">
<dl>
<dt><tt class="REPLACEABLE"><i>name</i></tt></dt>
<dd><p>要创建的函数名字(可以用模式修饰)</p></dd>
<dt><tt class="REPLACEABLE"><i>argmode</i></tt></dt>
<dd><p>参数的模式：<tt class="LITERAL">IN</tt>(缺省), <tt class="LITERAL">OUT</tt>, <tt class="LITERAL">INOUT</tt></p></dd>
<dt><tt class="REPLACEABLE"><i>argname</i></tt></dt>
<dd><p>一个参数的名字。有些语言(目前只有 PL/pgSQL)允许你在函数体里使用参数名字。对于其它语言，这个参数名字只是额外的文档。但是输出参数的名字是非常重要的，因为它定义了结果行类型的字段名。如果你省略了输出参数的名字，那么系统会自动选择一个缺省名字。</p></dd>
<dt><tt class="REPLACEABLE"><i>argtype</i></tt></dt>
<dd><p>该函数的数据类型(可以有模式修饰)，如果有的话。可以是基本类型，也可以是复合类型、域类型、或者可以引用一个现有字段相同的类型。</p>
<p>根据实现语言的不同，还可以在这上面声明"伪类型"(比如 <tt class="TYPE">cstring</tt>)。伪类型表示实际的参数类型要么是没有完整地声明，要么是在普通的 SQL 数据类型之外。</p>
<p>一个字段的类型是用 <tt class="LITERAL"><tt class="REPLACEABLE"><i>tablename</i></tt>.<tt class="REPLACEABLE"><i>columnname</i></tt>%TYPE</tt> 表示的；使用这个特性有时候可以帮助创建一个不受表定义变化影响的函数。</p></dd>
<dt><tt class="REPLACEABLE"><i>rettype</i></tt></dt>
<dd><p>返回值的数据类型。可以声明为一个基本类型、复合类型、域类型、或者引用一个表的现有字段。根据实现语言的不同，还可以在这上面声明"伪类型"(比如 <tt class="TYPE">cstring</tt>)。如果不打算返回任何值可以指定 <tt class="TYPE">void</tt> 作为返回类型。</p>
<p>如果存在 <tt class="LITERAL">OUT</tt> 或 <tt class="LITERAL">INOUT</tt> 参数，那么可以省略 <tt class="LITERAL">RETURNS</tt> 子句。如果出现了，那么它必须隐含的和输出参数结果类型兼容：如果有多个输出参数，则必须是 <tt class="LITERAL">RECORD</tt> ，如果只有一个输出参数，则与其相同。</p>
<p><tt class="LITERAL">SETOF</tt> 修饰词表示该函数将返回一个集合，而不是单独一项。</p>
<p>一个字段的类型是通过 <tt class="LITERAL"><tt class="REPLACEABLE"><i>tablename</i></tt>.<tt class="REPLACEABLE"><i>columnname</i></tt>%TYPE</tt> 引用的。</p></dd>
<dt><tt class="REPLACEABLE"><i>langname</i></tt></dt>
<dd><p>用以实现函数的语言的名字。可以是 <tt class="LITERAL">SQL</tt>, <tt class="LITERAL">C</tt>, <tt class="LITERAL">internal</tt> ，或者是用户定义的过程语言名字。为了保持向下兼容，该名字可以用单引号包围。</p></dd>
<dt><tt class="LITERAL">IMMUTABLE</tt><br><tt class="LITERAL">STABLE</tt><br><tt class="LITERAL">VOLATILE</tt></dt>
<dd><p>这些属性告诉系统把对该函数的多次调用替换成一次是否安全，主要用于运行时优化。缺省是 <tt class="LITERAL">VOLATILE</tt> 。</p>
<p><tt class="LITERAL">IMMUTABLE</tt> 表示该函数不能修改数据库，并且在给出同样的参数值时总是返回同样的结果；也就是说，它不查询数据库或者只使用那些没有出现在参数列表里的信息。如果给出这个选项，那么任何全部使用常数对该函数的调用都将立即替换为该函数的值。</p>
<p><tt class="LITERAL">STABLE</tt>  表示该函数不能修改数据库，对相同参数值，在同一次表扫描里，该函数的返回值不变，但是返回值可能在不同 SQL 语句之间变化。这个选项对那些结果依赖数据库查找、参数变量(比如当前时区)之类的函数很合适。还要注意 <code class="FUNCTION">current_timestamp</code> 函数族是稳定的，因为它们的值在一次事务中不会变化。</p>
<p><tt class="LITERAL">VOLATILE</tt> 表示该函数值甚至可以在一次表扫描内改变，因此不会做任何优化。只有很少的数据库函数在这个概念上是易变的；一些例子是 <tt class="LITERAL">random()</tt>, <tt class="LITERAL">currval()</tt>, <tt class="LITERAL">timeofday()</tt> 。请注意任何有副作用的函数都必需列为易变类，即使其结果相当有规律也应该这样，这样才能避免它被优化；一个例子就是 <tt class="LITERAL">setval()</tt> 。</p>
<p>更多细节，请参阅<a href="xfunc-volatility.html">节33.6</a>。</p></dd>
<dt><tt class="LITERAL">CALLED ON NULL INPUT</tt><br><tt class="LITERAL">RETURNS NULL ON NULL INPUT</tt><br><tt class="LITERAL">STRICT</tt></dt>
<dd><p><tt class="LITERAL">CALLED ON NULL INPUT</tt>(缺省)表明该函数在自己的某些参数是 NULL 的时候还是可以按照正常的方式调用。函数的作者必须负责检查 NULL 以及相应地做出反应。</p>
<p><tt class="LITERAL">RETURNS NULL ON NULL INPUT</tt> 或 <tt class="LITERAL">STRICT</tt> 表明如果它的任何参数是 NULL ，此函数总是返回 NULL 。如果声明了这个参数，则如果存在 NULL 参数时不会执行该函数；而只是自动假设一个 NULL 结果。</p></dd>
<dt><tt class="LITERAL">[<span class="OPTIONAL">EXTERNAL</span>] SECURITY INVOKER</tt><br><tt class="LITERAL">[<span class="OPTIONAL">EXTERNAL</span>] SECURITY DEFINER</tt></dt>
<dd><p><tt class="LITERAL">SECURITY INVOKER</tt>(缺省)表明该函数将带着调用它的用户的权限执行。<tt class="LITERAL">SECURITY DEFINER</tt> 声明该函数将以创建它的用户的权限执行。</p>
<p>关键字 <tt class="LITERAL">EXTERNAL</tt> 的目的是和 SQL 兼容，但是它是可选的，因为这个特性适合于所有函数，而不仅仅外部函数。</p></dd>
<dt><tt class="REPLACEABLE"><i>definition</i></tt></dt>
<dd><p>一个定义函数的字符串常量，含义取决于语言。它可以是一个内部函数名字、一个指向某个目标文件的路径、一个 SQL 查询、一个过程语言文本。</p></dd>
<dt><tt class="LITERAL"><tt class="REPLACEABLE"><i>obj_file</i></tt>, <tt class="REPLACEABLE"><i>link_symbol</i></tt></tt></dt>
<dd><p>这个形式的 <tt class="LITERAL">AS</tt> 子句用于在函数的 C 源文件里的名字和 SQL 名字不同时可动态加载 C 语言函数。字符串 <tt class="REPLACEABLE"><i>obj_file</i></tt> 是包含可动态加载对象的文件名，而 <tt class="REPLACEABLE"><i>link_symbol</i></tt> 是函数的链接符号，也就是该函数在 C 源文件里的名字。如果省略了链接符号，那么就假设它和被定义的 SQL 函数同名。</p></dd>
<dt><tt class="REPLACEABLE"><i>attribute</i></tt></dt>
<dd><p>历史遗留的函数可选信息。下面的属性可以在此出现：</p>
<div class="VARIABLELIST">
<dl>
<dt><tt class="LITERAL">isStrict</tt></dt>
<dd><p>等效于 <tt class="LITERAL">STRICT</tt> 或 <tt class="LITERAL">RETURNS NULL ON NULL INPUT</tt></p></dd>
<dt><tt class="LITERAL">isCachable</tt></dt>
<dd><p><tt class="LITERAL">isCachable</tt> 是 <tt class="LITERAL">IMMUTABLE</tt> 的过时的等效物；不过出于向下兼容，仍然接受它。</p></dd>
</dl>
</div>
<p>属性名是大小写无关的。</p></dd>
</dl>
</div>
</div>
<div class="REFSECT1"><a name="SQL-CREATEFUNCTION-NOTES"></a><h2>注意</h2>
<p>请参阅<a href="xfunc.html">节33.3</a>获取更多关于书写函数的信息。</p>
<p>允许你将完整的 SQL 类型语法用于输入参数和返回值。不过，有些类型声明的细节(比如 <tt class="TYPE">numeric</tt> 类型的精度域)是由下层函数实现负责的，并且会被 <tt class="COMMAND">CREATE FUNCTION</tt> 命令悄悄地吞掉(也就是不再被识别或强制)。</p>
<p>PostgreSQL 允许函数<i class="FIRSTTERM">重载</i>；也就是只要输入参数不同，几个不同的函数可以同名。不过，所有函数的 C 名字必须不同，也就是说你必须给予重载的 C 函数不同的 C 名字(比如，使用参数类型作为 C 名字的一部分)。</p>
<p>如果两个函数同名，并且<span class="emphasis"><i class="EMPHASIS">输入</i></span>参数类型也相同，那么就认为这两个函数是一样的，忽略所有 <tt class="LITERAL">OUT</tt> 参数。因此，下面的声明是冲突的：</p>
<pre class="PROGRAMLISTING">CREATE FUNCTION foo(int) ...
CREATE FUNCTION foo(int, out text) ...</pre>
<p>如果重复调用 <tt class="COMMAND">CREATE FUNCTION</tt> 并且都指向同一个目标文件，那么该文件只加载一次。要重新加载该文件(可能是在开发过程中)，可以使用 <a href="sql-load.html"><i>LOAD</i></a> 命令。</p>
<p>使用 <a href="sql-dropfunction.html"><i>DROP FUNCTION</i></a> 删除一个用户定义函数。</p>
<p>通常，使用美元符界定(参阅 <a href="sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING">节4.1.2.2</a>)书写函数定义字符串，而不是使用普通的单引号包围语法会更方便。如果不使用美元符界定，那么函数体里面的任何单引号或反斜杠都必须用双写的方法逃逸。</p>
<p>要能定义函数，用户必须对该语言有 <tt class="LITERAL">USAGE</tt> 权限。</p>
</div>
<div class="REFSECT1"><a name="SQL-CREATEFUNCTION-EXAMPLES"></a><h2>例子</h2>
<p>这里是一些简单的例子，用于帮助你开始掌握这个命令。更多信息和例子，参阅<a href="xfunc.html">节33.3</a>。</p>
<pre class="PROGRAMLISTING">CREATE FUNCTION add(integer, integer) RETURNS integer
    AS 'select $1 + $2;'
    LANGUAGE SQL
    IMMUTABLE
    RETURNS NULL ON NULL INPUT;</pre>
<p>利用参数名用 PL/pgSQL 自增一个整数：</p>
<pre class="PROGRAMLISTING">CREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$
        BEGIN
                RETURN i + 1;
        END;
$$ LANGUAGE plpgsql;</pre>
<p>返回一个包含多个输出参数的记录：</p>
<pre class="PROGRAMLISTING">CREATE FUNCTION dup(in int, out f1 int, out f2 text)
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);</pre>
<p>你可以通过命名明确的复合类型的访法冗长地干同样的事情：</p>
<pre class="PROGRAMLISTING">CREATE TYPE dup_result AS (f1 int, f2 text);

CREATE FUNCTION dup(int) RETURNS dup_result
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);</pre>
</div>
<div class="REFSECT1"><a name="SQL-CREATEFUNCTION-COMPAT"></a><h2>兼容性</h2>
<p>它和 SQL:1999 里的 <tt class="COMMAND">CREATE FUNCTION</tt> 命令类似但是不兼容。属性和可以使用的语言都是不可移植的。</p>
<p>为了和一些其它的数据库系统兼容，<tt class="REPLACEABLE"><i>argmode</i></tt> 可以在 <tt class="REPLACEABLE"><i>argname</i></tt> 之前或者之后写，但是只有第一种访法是标准兼容的。</p>
</div>
<div class="REFSECT1"><a name="AEN47358"></a><h2>又见</h2><a href="sql-alterfunction.html"><i>ALTER FUNCTION</i></a>, <a href="sql-dropfunction.html"><i>DROP FUNCTION</i></a>, <a href="sql-grant.html"><i>GRANT</i></a>, <a href="sql-load.html"><i>LOAD</i></a>, <a href="sql-revoke.html"><i>REVOKE</i></a>, <a href="app-createlang.html"><i><i>createlang</i></i></a></div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="sql-createdomain.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="sql-creategroup.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">CREATE DOMAIN</td><td width="34%" align="center" valign="top"><a href="sql-commands.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">CREATE GROUP</td></tr>
</table>
</div>
</body></html>